package com.zoe.onelink.feign.autoconfigure;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RuntimeUtil;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration;
import com.alibaba.cloud.nacos.ribbon.NacosRule;
import com.alibaba.fastjson.JSON;
import com.netflix.loadbalancer.IRule;
import com.zoe.onelink.feign.listener.NacosInstancesChangeNotifier;
import com.zoe.onelink.feign.loadbalancer.OnelinkDevLoadBalanceRule;
import com.zoe.onelink.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.core.env.Environment;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2021</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2021-12-21
 */
@AutoConfigureBefore(NacosDiscoveryAutoConfiguration.class)
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({IRule.class, NacosRule.class})
@EnableConfigurationProperties(AppProperties.class)
@Slf4j
public class OnelinkFeignNacosAutoConfiguration {
    private static final Logger LOGGER = LoggerFactory.getLogger(OnelinkFeignNacosAutoConfiguration.class);
    private static final String KEY_START_TIME = "startup.time";
    private static final String KEY_OS_NAME = "os.name";
    private static final String KEY_USER_NAME = "user.name";
    private static final String KEY_GIT_NAME = "user.alias";
    private static final String KEY_VERSION = "version";
    private static final String KEY_ARTIFACT_ID = "artifact.id";
    private static final String KEY_PREFIX_APP_VERSION = "app.version.";

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @ConditionalOnMissingBean
    public IRule nacosRule(Environment env) {
        String[] activeProfiles = env.getActiveProfiles();
        if (activeProfiles.length == 0) {
            log.warn("使用默认的Profiles环境隔离将不会生效,如果是开发阶段,请在参数中指定spring.profiles.active=dev或者test");
        }
        boolean isDevOrTest = false;
        for (String activeProfile : activeProfiles) {
            if ("dev".equals(activeProfile) || "test".equals(activeProfile)) {
                isDevOrTest = true;
                log.info("[OneLinkFrm] 开启环境隔离负载策略: OnelinkDevLoadBalanceRule");
                break;
            }
        }
        return isDevOrTest ? new OnelinkDevLoadBalanceRule() : new NacosRule();
    }


    /**
     * nacos上报示例元数据信息:启动时间/操作系统/项目版本/主机用户(windows下体现) 等配置信息
     */
    @Bean
    @ConditionalOnMissingBean
    public NacosDiscoveryProperties nacosDiscoveryProperties(AppProperties appProperties) {

        NacosDiscoveryProperties nacosDiscoveryProperties = new NacosDiscoveryProperties();
        Map<String, String> metadata = nacosDiscoveryProperties.getMetadata();
        metadata.put(KEY_START_TIME, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                .format(new Date()));
        String osName = System.getProperty(KEY_OS_NAME);
        metadata.put(KEY_OS_NAME, osName);
        // windows下输出用户， 方便nacos注册中心定位到研发人员
        if (osName.toLowerCase().contains("windows")) {
            metadata.put(KEY_USER_NAME, System.getProperty(KEY_USER_NAME));
            String gitUser = this.getGitUsername();
            metadata.put(KEY_GIT_NAME, gitUser);
        }
        // 当前项目maven version的版本号还未规范起来,暂时使用分支名称体现当前版本
        String version = appProperties.getBranchName();
        if (!version.contains("@")) {
            metadata.put(KEY_VERSION, version);
        }
        if (!appProperties.getArtifactId().contains("@")) {
            metadata.put(KEY_ARTIFACT_ID, appProperties.getArtifactId());
        }
        if (!MapUtil.isEmpty(appProperties.getVersion())) {
            for (Map.Entry<String, String> item : appProperties.getVersion().entrySet()) {
                if (StrUtil.contains(item.getValue(), "@")) {
                    continue;
                }
                metadata.put(KEY_PREFIX_APP_VERSION + item.getKey(), item.getValue());
            }
        }
        LOGGER.info("[OneLinkFrm] 开启服务元数据上报 Nacos MetaData:{}", JSON.toJSONString(metadata));
        return nacosDiscoveryProperties;
    }

    private String getGitUsername() {
        try {
            String gitUsername = StrUtil.removeSuffix(RuntimeUtil.execForStr("git config user.name"), "\n");
            return gitUsername == null ? "" : gitUsername;
        } catch (Exception e) {
            // ignore
        }
        return "-";
    }


    @Bean
    public NacosInstancesChangeNotifier nacosInstancesChangeNotifier(SpringClientFactory springClientFactory, Environment environment) {
        String applicationName = environment.getProperty("spring.application.name", "");
        return new NacosInstancesChangeNotifier(springClientFactory, applicationName);
    }


}
